# 使用真实嵌入模型的优化版本（修复版）
# -- coding: utf-8 --
import sys
import io
from dotenv import load_dotenv

# 设置标准输出的编码为UTF-8
if sys.stdout.encoding != "UTF-8":
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")

import numpy as np
import os
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import (
    RecursiveCharacterTextSplitter,
    CharacterTextSplitter,
    TokenTextSplitter,
)
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS

load_dotenv()


def create_sample_documents():
    """创建示例文档用于分割演示"""
    print("\n📁 创建示例文档")
    print("-" * 40)
    os.makedirs("documents", exist_ok=True)

    sample_content = """人工智能技术全面解析

第一章：机器学习基础

1.1 什么是机器学习
机器学习是人工智能的一个核心领域，它使计算机系统能够从数据中学习和改进，而无需进行明确的编程。机器学习算法通过分析大量数据来识别模式并做出预测或决策。

1.2 主要机器学习类型
监督学习：使用标记数据训练模型，用于分类和回归任务。常见的算法包括线性回归、逻辑回归、支持向量机和决策树。

无监督学习：在未标记数据中发现隐藏模式，用于聚类和关联分析。常见算法包括K均值聚类、主成分分析和关联规则学习。

强化学习：智能体通过与环境互动学习最优行为策略，通过试错获得奖励最大化。代表性算法包括Q学习和深度强化学习。

第二章：深度学习进阶

2.1 神经网络基础
神经网络受人脑结构启发，由相互连接的神经元组成。前馈神经网络是最基本的类型，信息单向流动从输入层到输出层。

2.2 卷积神经网络(CNN)
CNN专门用于处理网格状数据，如图像。它通过卷积层、池化层和全连接层自动提取图像特征，在计算机视觉领域取得突破性成果。

2.3 循环神经网络(RNN)
RNN适合处理序列数据，具有记忆功能。LSTM和GRU是RNN的变体，解决了长序列训练中的梯度消失问题，广泛应用于自然语言处理和时间序列预测。

第三章：大语言模型与应用

3.1 Transformer架构
Transformer是当前大语言模型的基础架构，采用自注意力机制并行处理序列数据，大幅提高了训练效率和模型性能。

3.2 预训练与微调
大语言模型通常先在大规模语料上进行预训练，学习通用语言表示，然后在特定任务上进行微调，适应具体应用场景。

3.3 RAG技术详解
检索增强生成(RAG)结合了信息检索和文本生成，通过从外部知识库检索相关信息来增强LLM的回答准确性和事实性，有效减少幻觉问题。

第四章：实际应用场景

4.1 智能客服系统
基于自然语言处理技术，智能客服能够理解用户问题并提供准确回答，大幅提高客户服务效率和满意度。

4.2 内容生成与创作
AI写作助手可以帮助创作者生成文章草稿、营销文案、代码注释等，提高创作效率和质量。

4.3 数据分析与洞察
机器学习算法能够从海量数据中提取有价值的信息和模式，为商业决策提供数据支持。"""

    with open("documents/ai_comprehensive_guide_real.txt", "w", encoding="utf-8") as f:
        f.write(sample_content)

    print("✅ 已创建综合示例文档: documents/ai_comprehensive_guide_real.txt")
    return "documents/ai_comprehensive_guide_real.txt"


def document_splitting_demo():
    """文档分割演示"""
    print("\n✂️ 文档分割演示")
    print("-" * 40)

    # 加载文档
    text_path = "documents/ai_comprehensive_guide_real.txt"
    loader = TextLoader(text_path, encoding="utf-8")
    documents = loader.load()

    original_doc = documents[0]
    print(f"📄 原始文档信息:")
    print(f"   内容长度: {len(original_doc.page_content)} 字符")
    print(f"   预估段落数: {original_doc.page_content.count(chr(10) + chr(10)) + 1}")

    # 演示不同的分割方法
    print("\n1. 按字符分割")
    print("-" * 20)

    char_splitter = CharacterTextSplitter(
        separator="\n\n",
        chunk_size=300,
        chunk_overlap=50,
        length_function=len,
        is_separator_regex=False,
    )

    char_chunks = char_splitter.split_text(original_doc.page_content)
    print(f"   生成块数: {len(char_chunks)}")
    for i, chunk in enumerate(char_chunks[:3]):
        print(f"   块 {i+1}: {len(chunk)} 字符")
        print(f"     预览: {chunk[:80]}...")

    print("\n2. 递归字符分割（推荐）")
    print("-" * 20)

    recursive_splitter = RecursiveCharacterTextSplitter(
        chunk_size=400,
        chunk_overlap=80,
        length_function=len,
        separators=["\n\n", "\n", "。", "，", " ", ""],
    )

    recursive_chunks = recursive_splitter.split_text(original_doc.page_content)
    print(f"   生成块数: {len(recursive_chunks)}")

    # 显示分割效果
    for i, chunk in enumerate(recursive_chunks[:3]):
        print(f"\n   📍 块 {i+1}:")
        print(f"      长度: {len(chunk)} 字符")
        print(f"      内容: {chunk[:100]}...")
        print(f"      元数据: 来自文档 '{original_doc.metadata['source']}'")

    return {
        "original": original_doc,
        "char_chunks": char_chunks,
        "recursive_chunks": recursive_chunks,
    }


class SimpleEmbeddings:
    """简单的本地嵌入模型，避免网络连接问题"""

    def __init__(self, dimension=384):
        self.dimension = dimension
        # 预定义一些关键词的简单向量表示
        self.keyword_vectors = {
            "机器学习": [0.8, 0.2, 0.1] + [0] * (dimension - 3),
            "深度学习": [0.1, 0.8, 0.2] + [0] * (dimension - 3),
            "神经网络": [0.2, 0.1, 0.8] + [0] * (dimension - 3),
            "人工智能": [0.7, 0.3, 0.2] + [0] * (dimension - 3),
            "监督学习": [0.6, 0.4, 0.1] + [0] * (dimension - 3),
            "无监督学习": [0.4, 0.6, 0.1] + [0] * (dimension - 3),
            "强化学习": [0.5, 0.5, 0.3] + [0] * (dimension - 3),
            "Transformer": [0.3, 0.7, 0.4] + [0] * (dimension - 3),
            "RAG": [0.4, 0.3, 0.7] + [0] * (dimension - 3),
        }

    def embed_documents(self, texts):
        """为文档生成嵌入向量"""
        vectors = []
        for text in texts:
            # 简单的基于关键词的向量生成
            vector = np.zeros(self.dimension)
            word_count = 0

            for keyword, keyword_vector in self.keyword_vectors.items():
                if keyword in text:
                    vector += np.array(keyword_vector)
                    word_count += 1

            if word_count > 0:
                vector = vector / word_count  # 平均
            else:
                vector = np.random.normal(0, 0.1, self.dimension)  # 随机向量

            vectors.append(vector.tolist())

        return vectors

    def embed_query(self, text):
        """为查询生成嵌入向量"""
        return self.embed_documents([text])[0]

    def __call__(self, input):
        """使对象可调用，兼容FAISS接口"""
        if isinstance(input, list):
            return self.embed_documents(input)
        else:
            return self.embed_query(input)


def real_embedding_vectorization_demo():
    """使用真实嵌入模型的向量化演示"""
    print("\n🔢 真实嵌入模型向量化演示")
    print("-" * 40)

    try:
        # 使用真实嵌入模型 - 选择一个适合中文的小型模型
        print("🔄 加载 sentence-transformers 嵌入模型...")

        model_name = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"

        embeddings = HuggingFaceEmbeddings(
            model_name=model_name,
            model_kwargs={"device": "cpu"},
            encode_kwargs={"normalize_embeddings": True},
        )

        # 测试文本
        test_texts = [
            "机器学习是人工智能的核心技术",
            "深度学习使用神经网络处理复杂模式",
            "今天天气很好，适合户外运动",
            "监督学习需要标记数据进行训练",
            "无监督学习可以发现数据中的隐藏模式",
        ]

        print("🧪 生成文本向量...")
        vectors = embeddings.embed_documents(test_texts)
        print(f"✅ 成功生成 {len(vectors)} 个文本向量")
        print(f"📊 向量维度: {len(vectors[0])} 维")

        # 显示向量信息和相似度计算
        print("\n📈 语义相似度分析:")
        for i, (text, vector) in enumerate(zip(test_texts, vectors)):
            print(f"\n   文本 {i+1}: {text}")
            # 只显示前5个维度
            preview = ", ".join([f"{v:.4f}" for v in vector[:5]])
            print(f"   向量预览: [{preview}, ...]")
            print(f"   向量范数: {np.linalg.norm(vector):.4f}")

        # 计算相似度矩阵
        print("\n🔍 语义相似度矩阵:")
        similarity_matrix = np.zeros((len(test_texts), len(test_texts)))
        for i in range(len(test_texts)):
            for j in range(len(test_texts)):
                # 余弦相似度
                similarity = np.dot(vectors[i], vectors[j]) / (
                    np.linalg.norm(vectors[i]) * np.linalg.norm(vectors[j])
                )
                similarity_matrix[i][j] = similarity

        # 打印相似度矩阵
        print("   " + " ".join([f"{i+1:>6}" for i in range(len(test_texts))]))
        for i in range(len(test_texts)):
            row = f"{i+1:>2} "
            for j in range(len(test_texts)):
                row += f"{similarity_matrix[i][j]:.3f} "
            print(f"   {row}")

        print("\n💡 相似度解读:")
        print("   - 接近1.0: 语义非常相似")
        print("   - 接近0.0: 语义不相关")
        print("   - 负数: 语义相反")

        return embeddings
    except Exception as e:
        print(f"❌ 真实嵌入模型加载失败: {e}")
        print("🔄 使用本地简单嵌入模型作为替代...")

        # 使用本地简单嵌入模型
        embeddings = SimpleEmbeddings(dimension=384)

        # 测试文本
        test_texts = [
            "机器学习是人工智能的核心技术",
            "深度学习使用神经网络处理复杂模式",
            "今天天气很好，适合户外运动",
            "监督学习需要标记数据进行训练",
            "无监督学习可以发现数据中的隐藏模式",
        ]

        print("🧪 使用本地模型生成文本向量...")
        vectors = embeddings.embed_documents(test_texts)
        print(f"✅ 成功生成 {len(vectors)} 个文本向量")
        print(f"📊 向量维度: {len(vectors[0])} 维")

        # 显示向量信息
        for i, (text, vector) in enumerate(zip(test_texts, vectors)):
            print(f"\n   文本 {i+1}: {text}")
            # 只显示前5个维度
            preview = ", ".join([f"{v:.4f}" for v in vector[:5]])
            print(f"   向量预览: [{preview}, ...]")
            print(f"   向量范数: {np.linalg.norm(vector):.4f}")

        return embeddings


def create_advanced_vector_store(split_docs, embeddings):
    """创建高级向量存储并进行语义搜索"""
    print("\n🗄️ 高级向量数据库创建")
    print("-" * 40)

    if not embeddings:
        print("❌ 请先完成嵌入模型初始化")
        return None

    try:
        # 使用分割后的文档创建向量数据库
        texts = split_docs["recursive_chunks"]
        print(f"📝 使用 {len(texts)} 个文本块创建向量数据库...")

        # 创建FAISS向量存储
        vectorstore = FAISS.from_texts(
            texts=texts,
            embedding=embeddings,
            metadatas=[
                {"source": "ai_guide", "chunk_id": i, "strategy": "recursive"}
                for i in range(len(texts))
            ],
        )

        print("✅ 向量数据库创建成功!")
        print(f"📊 索引大小: {vectorstore.index.ntotal} 个向量")

        # 演示高级搜索功能
        print("\n🔍 高级语义搜索演示")
        print("-" * 25)

        # 不同类型的查询测试
        test_cases = [
            {"query": "机器学习", "description": "关键词搜索"},
            {"query": "人工智能如何学习", "description": "自然语言问题"},
            {"query": "神经网络类型", "description": "技术概念搜索"},
            {"query": "AI应用场景", "description": "应用领域搜索"},
        ]

        for case in test_cases:
            print(f"\n   🔎 {case['description']}: '{case['query']}'")
            results = vectorstore.similarity_search(case["query"], k=2)

            for i, doc in enumerate(results):
                # 计算真实相似度（使用嵌入模型）
                query_embedding = embeddings.embed_query(case["query"])
                doc_embedding = embeddings.embed_query(doc.page_content)
                similarity = np.dot(query_embedding, doc_embedding) / (
                    np.linalg.norm(query_embedding) * np.linalg.norm(doc_embedding)
                )

                content_preview = (
                    doc.page_content[:120] + "..."
                    if len(doc.page_content) > 120
                    else doc.page_content
                )
                print(f"      {i+1}. 相似度: {similarity:.2f} | {content_preview}")

        # 演示相似度阈值搜索
        print(f"\n🎯 相似度阈值搜索演示")
        print("-" * 30)

        # 使用相似度搜索带分数
        query = "深度学习"
        docs_and_scores = vectorstore.similarity_search_with_score(query, k=3)

        print(f"   查询: '{query}'")
        for i, (doc, score) in enumerate(docs_and_scores):
            similarity = 1 - score  # 转换为相似度分数
            print(f"      {i+1}. 相似度: {similarity:.3f}")
            print(f"         内容: {doc.page_content[:80]}...")

        return vectorstore
    except Exception as e:
        print(f"❌ 向量数据库创建失败: {e}")
        return None


def embedding_model_comparison():
    """嵌入模型比较演示"""
    print("\n⚖️ 嵌入模型比较")
    print("-" * 40)

    try:
        # 测试不同的嵌入模型（如果有多个）
        test_texts = ["机器学习", "深度学习", "神经网络", "监督学习"]

        # 使用本地简单模型进行比较
        embeddings = SimpleEmbeddings(dimension=384)

        print(f"🧪 测试模型: 本地简单嵌入模型")
        vectors = embeddings.embed_documents(test_texts)

        print("📊 相似度分析:")
        for i, text1 in enumerate(test_texts):
            similarities = []
            for j, text2 in enumerate(test_texts):
                sim = np.dot(vectors[i], vectors[j]) / (
                    np.linalg.norm(vectors[i]) * np.linalg.norm(vectors[j])
                )
                similarities.append(f"{sim:.3f}")
            print(f"   '{text1}' → [{', '.join(similarities)}]")

    except Exception as e:
        print(f"❌ 模型比较失败: {e}")


def practical_rag_demo(vectorstore, embeddings):
    """RAG应用场景演示"""
    print("\n🚀 RAG应用场景演示")
    print("-" * 40)

    if not vectorstore:
        print("❌ 需要先创建向量数据库")
        return

    # 模拟RAG问答场景
    scenarios = [
        {
            "question": "机器学习有哪些主要类型？请详细说明。",
            "context": "寻找机器学习分类信息",
        },
        {"question": "深度学习和机器学习有什么区别？", "context": "概念对比分析"},
        {"question": "神经网络在哪些领域有应用？", "context": "应用场景探索"},
        {"question": "什么是RAG技术？它有什么优势？", "context": "技术原理了解"},
    ]

    print("🤖 智能文档问答系统演示")
    print("-" * 30)

    for scenario in scenarios:
        print(f"\n❓ 用户问题: {scenario['question']}")
        print(f"   📋 场景: {scenario['context']}")

        # 检索相关文档
        results = vectorstore.similarity_search(scenario["question"], k=2)

        if results:
            print("   📚 检索到的相关知识:")
            for i, doc in enumerate(results):
                # 清理内容用于显示
                clean_content = doc.page_content.replace("\n", " ").strip()
                preview = (
                    clean_content[:100] + "..."
                    if len(clean_content) > 100
                    else clean_content
                )
                print(f"      {i+1}. {preview}")

            # 模拟LLM回答（这里只是演示，实际需要接入真实的LLM）
            print("   💡 基于检索内容的回答:")
            if "类型" in scenario["question"]:
                print(
                    "      根据文档，机器学习主要分为监督学习、无监督学习和强化学习三种类型..."
                )
            elif "区别" in scenario["question"]:
                print(
                    "      深度学习是机器学习的一个子集，专门使用神经网络处理复杂模式..."
                )
            elif "应用" in scenario["question"]:
                print(
                    "      神经网络在计算机视觉、自然语言处理、语音识别等领域有广泛应用..."
                )
            elif "RAG" in scenario["question"]:
                print(
                    "      RAG技术通过检索外部知识来增强语言模型的回答准确性和事实性..."
                )
        else:
            print("   ❌ 未找到相关信息")


def performance_optimization_tips():
    """性能优化建议"""
    print("\n⚡ 性能优化建议")
    print("-" * 40)

    tips = [
        "🔧 分割策略优化:",
        "   - chunk_size: 根据文档类型调整 (技术文档: 400-600, 对话文本: 200-300)",
        "   - chunk_overlap: 保持10-20%的重叠以确保上下文连贯",
        "   - 对于长文档，使用递归分割器效果最好",
        "",
        "🔧 嵌入模型选择:",
        "   - 中文文档: 选择支持多语言的模型",
        "   - 性能要求: 小型模型推理快，大型模型精度高",
        "   - 内存限制: 考虑模型大小和设备内存",
        "",
        "🔧 向量数据库优化:",
        "   - FAISS适合中小规模数据，Chromadb适合大规模",
        "   - 定期重建索引以优化搜索性能",
        "   - 考虑使用量化减少内存占用",
        "",
        "🔧 搜索策略:",
        "   - 使用相似度阈值过滤低质量结果",
        "   - 结合关键词搜索和语义搜索",
        "   - 对搜索结果进行重排序提高精度",
    ]

    for tip in tips:
        print(tip)


if __name__ == "__main__":
    print("🎯 Day 5 - 文档分割与向量化学习 (修复完整版)")
    print("=" * 50)

    # 创建示例文档
    create_sample_documents()

    # 文档分割演示 - 这是核心步骤！
    split_results = document_splitting_demo()

    # 使用真实嵌入模型进行向量化
    embeddings = real_embedding_vectorization_demo()

    # 创建高级向量数据库 - 需要分割结果和嵌入模型
    vectorstore = None
    if embeddings and split_results:
        vectorstore = create_advanced_vector_store(split_results, embeddings)

    # 嵌入模型比较
    embedding_model_comparison()

    # RAG应用演示 - 需要向量数据库和嵌入模型
    if vectorstore:
        practical_rag_demo(vectorstore, embeddings)

    # 性能优化建议
    performance_optimization_tips()

    print("\n" + "=" * 50)
    print("🎉 Day 5 学习完成！")
    print("\n📚 今日学习总结:")
    print("   ✅ 文档分割技术 - 掌握多种分割策略和参数调优")
    print("   ✅ 向量化处理 - 理解嵌入模型原理和应用")
    print("   ✅ 向量数据库 - 学会创建和检索向量")
    print("   ✅ RAG基础 - 构建检索增强生成系统原型")
    print("   ✅ 实际问题解决 - 处理网络连接和参数错误")

    print("\n🔧 核心技术要点:")
    print("   1. RecursiveCharacterTextSplitter - 最优分割策略")
    print("   2. 嵌入模型 - 文本到向量的转换")
    print("   3. FAISS - 高效的向量相似性搜索")
    print("   4. 语义相似度计算 - 余弦相似度等度量方法")
    print("   5. RAG流水线 - 检索+生成的完整流程")

    print("\n🚀 下一步学习:")
    print("   📍 Day 6: 集成DeepSeek完成完整RAG系统")
    print("   📍 Day 7: 对话记忆和上下文管理")
    print("   📍 Day 8: 项目部署和性能优化")

    print("\n💡 实践建议:")
    print("   1. 尝试不同的分割参数观察效果")
    print("   2. 使用自己的文档测试整个流程")
    print("   3. 当网络畅通时，尝试使用真实嵌入模型")
    print("   4. 探索其他向量数据库和搜索策略")
